package com.ddw.meedeeuh.shared.movie.filter;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import java.util.regex.Pattern;

import com.ddw.meedeeuh.shared.io.PathUtils;
import com.ddw.meedeeuh.shared.io.SourceFile;
import com.ddw.meedeeuh.shared.io.SourceFileFactory;
import com.ddw.meedeeuh.shared.io.SourceFolderFactory;
import com.ddw.meedeeuh.shared.movie.MovieSettings;

class MovieFilterImpl implements MovieFilter {

	private static final Logger LOGGER = Logger.getLogger(MovieFilterImpl.class.getName());
	private final MovieSettings settings;
	private final Map<String, Pattern> ignoreStrings;
	private final List<String> allowedMovieTypes;

	public MovieFilterImpl(MovieSettings settings, Map<String, Pattern> ignoreStrings, List<String> allowedMovieTypes) {
		this.settings = settings;
		this.ignoreStrings = ignoreStrings;
		this.allowedMovieTypes = allowedMovieTypes;
	}

	@Override
	public MovieFilterResult filter(File rootFile) {
		LOGGER.finer("Entering the movie filter routine");
		LOGGER.finest("Found movie folder: " + rootFile.getPath());

		// Format the file name
		LOGGER.finest("Parsing movie folder name");
		final String rootFileName = getMovieFileName(rootFile);
		LOGGER.finer("Movie folder name: " + rootFileName);

		// Get directory children
		LOGGER.finest("Getting movie folder children");
		final File[] rootFileChildren = rootFile.listFiles();
		if(rootFileChildren == null) {
			LOGGER.finest("Movie folder is a file or inaccessible, skipping");
			return MovieFilterResultFactory.create(null, null, null, null, false);
		}

		final List<File> rootFileChildrenFiles = new ArrayList<File>(rootFileChildren.length);
		final List<File> rootFileChildrenDirectories = new ArrayList<File>(rootFileChildren.length);

		// Filter the directory children
		LOGGER.finest("Searching for movie file match in movie folder");
		final FileFilter filter = new FileFilter() {

			@Override
			public boolean accept(File movieFile) {
				LOGGER.finest("Found movie file: " + movieFile.getPath());

				// Check it is a file
				LOGGER.finest("Checking movie file is a file");
				if(movieFile.isDirectory()) {
					LOGGER.finest("Movie file is a directory, skipping");
					rootFileChildrenDirectories.add(movieFile); // Add to directory cache
					return false;
				}
				LOGGER.finest("Movie file is a file");
				rootFileChildrenFiles.add(movieFile); // Add to file cache

				// Get the name, year and type
				LOGGER.finest("Parsing movie file name");
				final String movieFileName = getMovieFileName(movieFile);
				LOGGER.finer("Movie file name: " + movieFileName);

				LOGGER.finest("Getting movie file type");
				final String movieFileType = PathUtils.getExtension(movieFileName);
				LOGGER.finer("Movie file type: " + movieFileType);

				LOGGER.finest("Checking if movie type is allowed");
				final boolean movieTypeAllowed = allowedMovieTypes.contains(movieFileType);
				if(movieTypeAllowed == false) {
					LOGGER.finer("Movie file type is not allowed, skipping");
					return false;
				}

				LOGGER.finest(String.format("Checking if movie name is valid"));
				final boolean movieNameValid = settings.parentFolderNameMustMatchMovie() ?
						movieFileName.startsWith(rootFileName) : true;
				if(movieNameValid == false) {
					LOGGER.finer("Movie name is invalid, skipping");
					return false;
				}

				LOGGER.finer(String.format("Movie %s match success", movieFileName));
				return true;
			}

		};
		final List<SourceFile> movieSourceFiles = new ArrayList<SourceFile>(1); // Usually only 1 file
		for(int i = 0, s = rootFileChildren.length; i < s; i++) {
			final File rootFileChild = rootFileChildren[i];
			if(filter.accept(rootFileChild)) {
				movieSourceFiles.add(SourceFileFactory.create(rootFileChild));
			}
		}

		LOGGER.finer(String.format("Found %d movie files", movieSourceFiles.size()));
		LOGGER.finest("Exiting the movie filter routine");
		return MovieFilterResultFactory.create(SourceFolderFactory.create(rootFile), rootFileChildrenDirectories,
				rootFileChildrenFiles, movieSourceFiles, movieSourceFiles.size() > 0);
	}

	private String getMovieFileName(File file) {
		String name = file.getName().toLowerCase();
		for(final Pattern pattern : ignoreStrings.values()) {
			name = pattern.matcher(name).replaceAll("");
		}
		return name;
	}

}
